#include "ComplexProxyModel.h"



#include <ItemReference.h>



#include <QDebug>



ComplexProxyModel::ComplexProxyModel(QObject *parent) :
    SimpleProxyModel(parent)
{
}



QModelIndex ComplexProxyModel::index(int row, int column, const QModelIndex &proxyParent) const
{
    if (!hasIndex(row, column, proxyParent)) return QModelIndex();

    // search for top level indexes if parent is null.
    if (!proxyParent.isValid()) return SimpleProxyModel::index(row, column, proxyParent);

    if (!m_indexTree.contains(proxyParent)) return QModelIndex();

    IndexTreeIterator it(m_indexTree);
    while (it.hasNext())
    {
        it.next();
        if (it.key() != proxyParent) continue;

        IndexMapIterator it2(it.value());
        while (it2.hasNext())
        {
            it2.next();
            if (it2.value().row() != row || it2.value().column() != column) continue;

            //qDebug() << Q_FUNC_INFO << "Found index!";
            return it2.value();
        }

        //qDebug() << Q_FUNC_INFO << "Index not found!";
        return QModelIndex();
    }

    //qDebug() << Q_FUNC_INFO << "Index not found 2!";
    return QModelIndex();
}



QModelIndex ComplexProxyModel::parent(const QModelIndex &proxyChild) const
{
    if (!proxyChild.isValid()) return QModelIndex();

    if (m_indexMap.values().contains(proxyChild)) return QModelIndex();

    IndexTreeIterator it(m_indexTree);
    while (it.hasNext())
    {
        it.next();
        if (!it.value().values().contains(proxyChild)) continue;

        return it.key();
    }

    return QModelIndex();
}



int ComplexProxyModel::rowCount(const QModelIndex &proxyParent) const
{
    // top level row count
    if (!proxyParent.isValid()) return SimpleProxyModel::rowCount(proxyParent);



    if (!m_indexTree.contains(proxyParent)) return 0;

    int ret = m_indexTree.value(proxyParent).count();
    //qDebug() << Q_FUNC_INFO << proxyParent.data(Qt::EditRole).toString() << "has" << ret << "children";
    return ret;
}



int ComplexProxyModel::columnCount(const QModelIndex &proxyParent) const
{
    return SimpleProxyModel::columnCount(proxyParent);
}


QModelIndex ComplexProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    QModelIndex proxyIndex = SimpleProxyModel::mapFromSource(sourceIndex);
    if (proxyIndex.isValid()) return proxyIndex;

    IndexTreeIterator it(m_indexTree);
    while (it.hasNext())
    {
        it.next();
        if (!it.value().keys().contains(sourceIndex)) continue;

        return it.value().value(sourceIndex);
    }

    return QModelIndex();
}



QModelIndex ComplexProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
    QModelIndex sourceIndex = SimpleProxyModel::mapToSource(proxyIndex);
    if (sourceIndex.isValid()) return sourceIndex;

    IndexTreeIterator it(m_indexTree);
    while (it.hasNext())
    {
        it.next();

        if (!it.value().values().contains(proxyIndex)) continue;

        return it.value().key(proxyIndex);
    }

    return QModelIndex();
}



void ComplexProxyModel::addComplexFilter(const QString &idPattern, const int &filter)
{
    m_complexeds.insert(idPattern, filter);
}



int ComplexProxyModel::complexFilter(const QString &itemId) const
{
    int ret = NoFilter;
    foreach (const QString idPattern, m_complexeds.keys())
    {
        QRegExp regExp(idPattern);

        if (regExp.indexIn(itemId) == -1) continue;

        int filter = m_complexeds.value(idPattern);

        switch (filter)
        {
        case NoFilter:
            continue;

        case RegExpFilter:
            break;

        case ContainsFilter:
            if (!itemId.contains(idPattern)) continue;
            break;

        case StartsWithFilter:
            if (!itemId.startsWith(idPattern)) continue;
            break;

        case EndsWithFilter:
            if (!itemId.endsWith(idPattern)) continue;
            break;

        case TreeFilter:
        case ElevateFilter:
            break;

        default:
            continue;
        }

        if (ret < filter) ret = filter;
    }

    return ret;
}



void ComplexProxyModel::mapChildren(const QModelIndex &sourceParent, int start)
{
    ItemModel* model = itemModel();
    if (!model) return;

    QModelIndex sourceIndex = model->index(start, AbstractItem::IdData, sourceParent);

    while (sourceIndex.isValid())
    {
        QString itemId = sourceIndex.data(Qt::EditRole).toString();

        int include = includeFilter(itemId);
        int exclude = excludeFilter(itemId);

        if (include > exclude)
        {
            int complex = complexFilter(itemId);

            if (complex > include)
            {
                //qDebug() << Q_FUNC_INFO << "Map complex";
                mapComplex(sourceIndex, sourceParent, complex);
            }

            else
            {
                mapIndex(sourceIndex);
            }
            //qDebug() << Q_FUNC_INFO << itemId << include << exclude;
        }

        mapChildren(sourceIndex);
        sourceIndex = sourceIndex.sibling(sourceIndex.row()+1, sourceIndex.column());
    }
}



void ComplexProxyModel::mapComplex(const QModelIndex& sourceIndex, const QModelIndex& sourceParent, const int& filter)
{
    // for child additions...
    QModelIndex proxyParent = mapFromSource(sourceParent.sibling(sourceParent.row(), m_fields.keys().first()));
    if (!proxyParent.isValid()) return;


    if (filter == TreeFilter)
    {
        IndexMap indexMap;
        foreach (const int field, m_fields.keys())
        {
            QModelIndex fieldIndex = sourceIndex.sibling(sourceIndex.row(), field);
            if (!fieldIndex.isValid()) continue;

            indexMap.insert(fieldIndex, createIndex(indexMap.count(), m_fields.keys().indexOf(field), fieldIndex.internalPointer()));
        }

        m_indexTree.insert(proxyParent, indexMap);
    }
}



